#include "glwindow.h"


GLWindow::GLWindow(QWidget *parent) : QGLWidget(parent) {
    setMouseTracking(true);
    //startTimer(1000/FPS);
    button_down=false;
    currentView=0;
}

GLWindow* GLWindow::getInstance(){
    static GLWindow* inst=0;
    if(!inst)return inst=new GLWindow();
    else return inst;
}

void GLWindow::init_light(){
     const GLfloat light_ambient[]  = { 0.2f, 0.2f, 0.2f, 1.0f };
     const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
     //const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
     //const GLfloat light_position[] = { 128.0f, 1000.0f, 128.0f, 0.0f };

     glEnable(GL_NORMALIZE);
     glEnable(GL_LIGHTING);

     glEnable(GL_LIGHT0);
     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
     //glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
     //glLightfv(GL_LIGHT0, GL_POSITION, light_position);
}

void GLWindow::init_material(){
    const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
    const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
    const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
    const GLfloat high_shininess[] = { 100.0f };

    glEnable(GL_COLOR_MATERIAL);

    glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
    //glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    //glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
}



void GLWindow::initializeGL() {
    //entry point where OpenGL establishes context
    rend=RenderManager::getInstance();
    global=GlobalStates::getInstance();
    mainTool = ToolInvoker::getInstance();
    setCurrentView(VIEW_EDITOR_MODE);


    //Tests (uncomment to run)
    tester= new TestDriver(rend);
    tester->runStdTests();
    //tester->testBrush();
    //tester->testSelect();
    //tester->testMagicWand();



//    ProceduralTerrainTool::getInstance()
//           ->genTerrain("sin(sqrt(((x-128)*0.3)^2+((z-128)*0.3)^2))*20+20","fabs(sin(x)*256)","fabs(cos(y)*256)","fabs(sin(z)*256)",vector3<int>(0,0,0),vector3<int>(256,256,256));
    //->genTerrain("tan(x*0.01)+tan(z*0.01)","fabs(sin(x)*256)","fabs(cos(y)*256)","fabs(sin(z)*256)",vector3<int>(0,0,0),vector3<int>(256,256,256));

       glClearColor(1,1,1,1);
       glEnable(GL_CULL_FACE);
       glCullFace(GL_BACK);

       glEnable(GL_DEPTH_TEST);
       glDepthFunc(GL_LESS);

       glShadeModel(GL_FLAT);
       //glShadeModel(GL_SMOOTH);

       init_light();
       init_material();

       glEnableClientState(GL_NORMAL_ARRAY);
       glEnableClientState(GL_VERTEX_ARRAY);
       glEnableClientState(GL_COLOR_ARRAY);


}

void GLWindow::resizeGL(int width, int height) {
    global->setScreenResolution(width,height);
    currentView->resize(width,height);
}

void GLWindow::paintGL() {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      currentView->display();
      Drawing::beginOverlay();
      currentView->overlayDisplay();
      Drawing::endOverlay();
}

void GLWindow::mousePressEvent(QMouseEvent *event) {
    event->accept();
    if (getCurrentView() == VIEW_GAME_MODE) {
        if (!hasMouseTracking()) {
            setMouseTracking(true);
        }
    }
    Result r = currentView->mousePressEvent(event);
    emit updateStatus(r.getMessageCStr());

    updateGL();
}

void GLWindow::mouseReleaseEvent(QMouseEvent *event){
    event->accept();
    currentView->mouseReleaseEvent(event);
    updateGL();
}

void GLWindow::mouseMoveEvent(QMouseEvent *event) {
    event->accept();
    currentView->mouseMoveEvent(event);
    updateGL();
}


void GLWindow::keyPressEvent(QKeyEvent* event) {
    event->accept();
    //if(event->key()==Qt::Key_Escape)close();
    if(event->key()==Qt::Key_0){
        if(getCurrentView()==VIEW_EDITOR_MODE)setCurrentView(VIEW_GAME_MODE);
        else setCurrentView(VIEW_EDITOR_MODE);
    } else if (event->key() == Qt::Key_P) {
        if (getCurrentView() == VIEW_GAME_MODE) {
            if (hasMouseTracking()) {
                setMouseTracking(false);
            } else {
                setMouseTracking(true);
            }
        }
    }
    Result r=currentView->keyPressEvent(event);
    emit updateStatus(r.getMessageCStr());
    updateGL();
}

void GLWindow::keyReleaseEvent(QKeyEvent* event) {
    event->accept();
   currentView->keyReleaseEvent(event);
    updateGL();
}

void GLWindow::enterEvent(QEvent *event){
    event->accept();
   currentView->mouseEnterEvent(event);
}

void GLWindow::leaveEvent(QEvent *event){
    event->accept();
   currentView->mouseLeaveEvent(event);
}

void GLWindow::wheelEvent(QWheelEvent *event){
    event->accept();
    currentView->mouseWheelEvent(event);
    updateGL();
}

void GLWindow::timerEvent(QTimerEvent *event){
    event->accept();
    currentView->timerEvent(event);
    updateGL();
}

RenderManager* GLWindow::getRenderManager() {
    return rend;
}

void GLWindow::setSelectedTool(Tool * tool) {
    mainTool->setSelectedTool(tool);
}
